//=====================================================================
//
// Designer   : fg
//
// Description:
//  5th CICIEC Nuclei Attendence Work
//	RISC-V Extension supported CIM mvm
// ====================================================================
`include "e203_defines.v"

    ////////////////////////////////////////////////////////////
	// NICE FSM 
	////////////////////////////////////////////////////////////
module nice_controller (
	///////// NICE Interface
	input                         clk             ,
	input                         rst_n	          ,
	output 						  nice_active     ,
	output 						  nice_mem_holdup ,

	input  [`E203_XLEN-1:0]       nice_req_inst   ,
	input 						  nice_req_valid  ,
	output 						  nice_req_ready  ,

	output                        nice_rsp_valid  ,
	input                         nice_rsp_ready  ,

	//done from datapath 
	input 						  push_done,
	input 						  mvm_done,
	input 						  save_done,
	
	//state to datapath
	output 						  custom3_push,
	output  					  custom3_mvm,
	output 						  custom3_save,
	output                        Isidle	  ,
	output                        Ispush	  ,
	output                        Ismvm	      ,
	output                        Issave	  
	);
	localparam NICE_FSM_WIDTH = 3; 
	localparam IDLE		= 3'd0; 
	localparam PUSH		= 3'd1;  
	localparam SAVE		= 3'd2; 
	localparam MVM	    = 3'd3;
	
	// here we only use custom3: 
	// CUSTOM0 = 7'h0b, R type
	// CUSTOM1 = 7'h2b, R tpye
	// CUSTOM2 = 7'h5b, R type
	// CUSTOM3 = 7'h7b, R type

	////////////////////////////////////////////////////////////
	// decode
	////////////////////////////////////////////////////////////
	wire [6:0] opcode      = nice_req_valid? nice_req_inst[6:0]	 :7'b0;
	wire [2:0] rv32_func3  = nice_req_valid? nice_req_inst[14:12]:3'b0;
	wire [6:0] rv32_func7  = nice_req_valid? nice_req_inst[31:25]:7'b0;

	reg [NICE_FSM_WIDTH-1:0]state,next;
	assign Isidle =   (state == IDLE)   ;
	assign Ispush =   (state == PUSH)	;
	assign Ismvm  =   (state == MVM) ;
	assign Issave =   (state == SAVE)	;

	wire opcode_custom3 = (opcode == 7'b1111011); 

	wire rv32_func3_000 = (rv32_func3 == 3'b000); 
	wire rv32_func3_001 = (rv32_func3 == 3'b001); 
	wire rv32_func3_010 = (rv32_func3 == 3'b010); 
	wire rv32_func3_011 = (rv32_func3 == 3'b011); 
	wire rv32_func3_100 = (rv32_func3 == 3'b100); 
	wire rv32_func3_101 = (rv32_func3 == 3'b101); 
	wire rv32_func3_110 = (rv32_func3 == 3'b110); 
	wire rv32_func3_111 = (rv32_func3 == 3'b111); 

	wire rv32_func7_0000001 = (rv32_func7 == 7'b0000001); 
	wire rv32_func7_0010001 = (rv32_func7 == 7'b0010001); 
    wire rv32_func7_0010010 = (rv32_func7 == 7'b0010010);
	assign custom3_push		= opcode_custom3 & rv32_func3_011 & (rv32_func7_0010001); 
	assign custom3_mvm		= opcode_custom3 & rv32_func3_011 & (rv32_func7_0000001); 
	assign custom3_save		= opcode_custom3 & rv32_func3_011 & (rv32_func7_0010010); 
  
	always@(*) begin
		case(state)
			IDLE:begin
				next = custom3_push? PUSH:(custom3_mvm? MVM:(custom3_save? SAVE:IDLE));
			end
			PUSH: begin
				next = push_done? IDLE:PUSH;
			end
			MVM: begin
				next = mvm_done? IDLE:MVM;
			end
			SAVE: begin
				next = save_done? IDLE:SAVE;
			end
			default: next = IDLE ;
		endcase
	end
	always @(posedge clk or negedge rst_n) begin 
		if(~rst_n) begin
			state <= #1 IDLE;
		end else begin
			state <= #1 next;
		end
	end

    assign nice_rsp_valid =  push_done|mvm_done|save_done;
	assign nice_mem_holdup = Ispush|Issave;
	assign nice_active     = Isidle? nice_req_valid:1'b1;
	assign nice_req_ready  = Isidle;

endmodule


